package com.cqcis.uip.base.framework.filters.adaptor;

import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
import org.apache.mina.transport.socket.nio.SocketConnector;

import com.cqcis.uip.base.framework.FrameworkConstants;
import com.cqcis.uip.base.framework.codec.ObjectDecodeException;
import com.cqcis.uip.base.framework.service.StreamNameUtil;
import com.cqcis.uip.base.framework.service.StreamOutput;
import com.cqcis.uip.base.framework.utils.ByteBuffer;


public abstract class AbstractProtocolObjectDecoder extends CumulativeProtocolDecoder {
	private static String CLOSED = "closed";
    private StreamNameUtil streamNameUtil; // 生成文件名
    private StreamOutput   streamOutput;  // 写文件
    
    @Override
    public void decode(IoSession session, org.apache.mina.common.ByteBuffer buffer,
    		ProtocolDecoderOutput output) throws Exception {
    	boolean hasBuffer = FrameworkConstants.VIRTUAL_NO_DATA_BUFFERS.remove(buffer);
    	if (hasBuffer) {
    		buffer = org.apache.mina.common.ByteBuffer.allocate(4).flip();
    	}
    	super.decode(session, buffer, output);
    }
        
	@Override
	/**
	 * 读取完整的socket数据包
	 * @see 
	 */
	protected boolean doDecode(IoSession session, org.apache.mina.common.ByteBuffer buffer,
			ProtocolDecoderOutput output) throws Exception {
		if (session.getAttribute(CLOSED) != null) {
			return false;
		}
		
		int oldpos = buffer.position();
		String fileName = null;
		Object outputObj = null;
		
		try {
			ByteBuffer buf = ByteBuffer.wrap(buffer);
			buf.setSession(session);
		    outputObj = doDecode(buf);
		    if (outputObj == null) {
		     	buffer.position(oldpos);
		    	return false;
		    }
		} catch (Throwable e) {
			buffer.position(oldpos);
			fileName = saveBufferAsFile(session, buffer);
			
			session.setAttribute(CLOSED, new Object());
			
			throw new ObjectDecodeException(e.getMessage() + ", data format error, close socket! fileName = " 
					+ fileName, e);
		}
				
		int currentpos = buffer.position();
		int packetLen = currentpos - oldpos;	
		
		buffer.position(oldpos);
		byte[] packetBuf = new byte[packetLen];
		buffer.get(packetBuf);
		
		fileName = saveBufferAsFile(session, ByteBuffer.wrap(packetBuf).toBuffer());
				
		buffer.position(currentpos);
		
		output.write(outputObj);
		
		return true;
	}
	
	/**
	 * 从给定的buffer里面读取需要的数据, 如果不能完整读出需要的数据, 返回null;
	 *                              出错, 则抛出异常
	 * @param buffer  
	 * @return
	 * @throws Exception
	 */
	protected abstract Object doDecode(com.cqcis.uip.base.framework.utils.ByteBuffer buffer) throws Exception;
	
	/**
	 * 保存为文件
	 * 
	 * @param session
	 * @param buffer
	 * @return
	 * @throws Exception
	 */
	private String saveBufferAsFile(IoSession session, org.apache.mina.common.ByteBuffer buffer) throws Exception {
		if (session.getAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD_CLOSED) != null) {
			return null;// 字节流功能已经关闭
		}
		// 判断当前session是否写二进制日志
		if (session.getAttribute(FrameworkConstants.STREAM_LOG_NOT_WRITED) != null) {
			session.setAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD, "STREAMLOG WRITE CLOSED");
			return null;
		}
		
		String file = null;				
		/*server*/
		if (session.getService() instanceof SocketAcceptor) {
			String filePath = streamNameUtil.getFilePath();
			session.setAttribute(StreamNameUtil.STREAM_FILE_PATH, filePath);
            
			if (filePath != null) {
				file = streamOutput.write(filePath, streamNameUtil.getRecvName(), buffer
						.buf());
			}
			
			session.setAttribute(StreamNameUtil.STREAM_NAME_SUFFIX,
					streamNameUtil.getPreFileSuffix());			
			
		} else if (session.getService() instanceof SocketConnector) {
			String filePath = (String) session
					.getAttribute(StreamNameUtil.STREAM_FILE_PATH);
			String nameSuffix = (String) session
					.getAttribute(StreamNameUtil.STREAM_NAME_SUFFIX);
            
			if (filePath != null && nameSuffix != null) {
				file = streamOutput.write(filePath,
						streamNameUtil.getRecvName(nameSuffix), buffer.buf());
			}
			
			session.removeAttribute(StreamNameUtil.STREAM_FILE_PATH);
			session.removeAttribute(StreamNameUtil.STREAM_NAME_SUFFIX);						
		}/*client*/	
		
		session.setAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD, file);
		
		return file;
	}
	
	public void registerStreamNameUtil(StreamNameUtil streamNameUtil) {
		this.streamNameUtil = streamNameUtil;
	}

	public void registerStreamOutput(StreamOutput streamOutput) {
		this.streamOutput = streamOutput;
	}

}
